package oop.ex1.filescript;

import java.io.*;
import java.util.*;

import oop.ex1.actions.*;

import oop.ex1.filters.*;

/**
 * a class that gets a source dir and a commands file and does desired action's on files that are matching the specifations given by the user.
 * then it prints the file acoording to the given order and prints the comments   
 * @author daniel shalev
 * @author dan almog
 */
public class MyFileScript {
	private static  ArrayList<Blocks> blocks;
	private static TreeSet<File> files;
	private static String defaultPath;
	
	/**
	 * @author danielshalev
	 * @author dan almog
	 * The filters names.
	 */
	public enum FiltersNames{
		after,
		before,
		file,
		greater_than,
		hidden,
		prefix,
		smaller_than,
		suffix,
		executable,
		writable;		
	}
	/**
	 * the order names
	 * @author danalmog
	 * @author danielshalev
	 */
	public enum OrderNames {
		abs,
		file,
		mod,
		size;
	}
	/**
	 * the actions names
	 * @author danalmog
	 * @author danielshalev
	 */
	public enum ActionsNames{
		copy,
		exec,
		last_mod,
		print_data,
		print_name,
		write;
	}
	
	/**
	 * filters the files accorrding to the relevant block
	 * @param source the source dir
	 * @param block the block which we work on
	 * @param inDir a boolean that chack's if we are inside a dir
	 */
	private static void filterFiles(File source,Blocks block, boolean inDir){
		Filters filter=new Filters(block.getFilters());
		File[] fileArr=source.listFiles();
		//checks if we used the recursion
		if (!inDir)
			defaultPath=new String(source.getAbsolutePath());
		//runs on all of the files
		for ( File f : fileArr ){
			//check if the file is a directory
			if(f.isDirectory())
				filterFiles(f,block,true);
			//check if the file has passed all the filters
			else if(filter.accept(f)){
				files.add(f);
			}
		}
	}
	
	/**
	 * a method that do the actions on all of the files that have been filtered
	 * @param block the block we are running on
	 * @throws BadActionExeption indicates if there is a problem with an action 
	 * @throws ActionYesNoExeption indicates if the relevant argument is neither YES nor NO  
	 * @throws CopyDirExeption indicates that there is problem with the copy directory
	 * @throws ActionDateException indicates that there is a problem with the date in an action
	 * @throws BadFileExeption indicates that there is a problem with a file
	 */
	private static void doAction(Blocks block) throws BadActionExeption, ActionYesNoExeption, CopyDirExeption, ActionDateException, BadFileExeption{
		Iterator<String> actionIter=block.getActions().iterator();	
		String next;
		//runs all over the action arrayList
		while(actionIter.hasNext()){
			Iterator<File> treeIter=files.iterator();
			Actions actionToDo;
			String argument=null;
			//saves the action name using the enum
			ActionsNames actionName=ActionsNames.valueOf((next=actionIter.next()).split("%")[0]);
			//checkes if the action has an argument and saves it
			if(next.contains("%"))
				argument=next.split("%")[1];
			switch (actionName) {
			//runs the desired action on all of the files
				case print_data:
					if (argument!=null)
						throw new BadActionExeption();
					while(treeIter.hasNext()){
						actionToDo=new PrintData(treeIter.next());
						actionToDo.doAction();
					}
					break;
				case print_name:
					if (argument!=null)
						throw new BadActionExeption();
					while(treeIter.hasNext()){
						actionToDo=new PrintName(treeIter.next());
						actionToDo.doAction();
					}
					break;
				case copy:
					while(treeIter.hasNext()){
						actionToDo=new Copy(defaultPath, argument,treeIter.next());
						actionToDo.doAction();
					}
					break;
				case exec:
					while(treeIter.hasNext()){
						actionToDo=new Exec(argument,treeIter.next());
						actionToDo.doAction();
					}
					break;
				case write:
					while(treeIter.hasNext()){
						actionToDo=new Write(argument,treeIter.next());
						actionToDo.doAction();
					}
					break;
				case last_mod:
					while(treeIter.hasNext()){
						actionToDo=new LastMod(argument,treeIter.next());
						actionToDo.doAction();
					}
					break;
				default:
					throw new BadActionExeption();
			}
		}
	}
	
	/**
	 * prints an error and exits the program
	 */
	private static void errorHandle(){
		System.err.println("ERROR");
		System.exit(-1);
	}

	/**
	 * gets a source dir and a commands file and does desired action's on files that are matching the specifations given by the user.
	 * then it prints the file according to the given order and prints the comments   
	 * @param args the source dir and command file
	 */
	public static void main(String[] args){
		try{
			//saves the source and command files
			File source=new File(args[0]);
			File commands=new File(args[1]);
			BlockParser tempParser=new BlockParser(commands);
			blocks=tempParser.getBlocks();
			//run on all of the blocks
			Iterator<Blocks> blockIter=blocks.iterator();
			while(blockIter.hasNext()){
				Blocks tempBlock=blockIter.next();
				files=new TreeSet<File>(tempBlock.getOreder());
				filterFiles(source,tempBlock,false);
				doAction(tempBlock);
				if(tempBlock.getComments()!=null)
					System.out.println(tempBlock.getComments());
			}				

		} catch (BadCommandFileExeption e){
			errorHandle();
		} catch (BadFilterExeption e) {
			errorHandle();
		} catch (BadOrderExeption e) {
			errorHandle();
		} catch (EmptyCommandFileExeption e) {
			errorHandle();
		} catch (FilterDateExeption e) {
			errorHandle();
		} catch (FilterYesNoExeption e) {
			errorHandle();
		} catch (BadActionExeption e) {
			errorHandle();
		} catch (ActionYesNoExeption e) {
			errorHandle();
		} catch (CopyDirExeption e) {
			errorHandle();
		} catch (ActionDateException e) {
			errorHandle();
		} catch (BadFileExeption e) {
			errorHandle();
		}		
	}
}
